#include <proc.h>
#include <elf.h>

#ifdef __LP64__
# define Elf_Ehdr Elf64_Ehdr
# define Elf_Phdr Elf64_Phdr
#else
# define Elf_Ehdr Elf32_Ehdr
# define Elf_Phdr Elf32_Phdr
#endif
size_t fs_open(const char *pathname,int flags,int mode);
size_t fs_read(int fd,void *buf,size_t len);
int fs_close(int fd);
size_t fs_lseek(int fd,size_t offset, int whence);
//size_t ramdisk_read(void *buf, size_t offset, size_t len);
//size_t get_ramdisk_size();
//static uintptr_t loader(PCB *pcb, const char *filename) {
//	Elf64_Ehdr elf_header;	
//	Elf64_Phdr program_header;
//	ramdisk_read(&elf_header,0,sizeof(elf_header));
//	assert(*((uint32_t*)elf_header.e_ident) ==1179403647);
//	for(int i=0;i<elf_header.e_phnum;i++){
//		ramdisk_read(&program_header,elf_header.e_phoff+i*sizeof(program_header),sizeof(program_header));
//		if(program_header.p_type == PT_LOAD){
//			ramdisk_read((void*)program_header.p_vaddr,program_header.p_offset,program_header.p_memsz);	
//			if(program_header.p_memsz >= program_header.p_filesz){
//				memset((void*)program_header.p_vaddr + program_header.p_filesz,0,program_header.p_memsz-program_header.p_filesz);
//			}
//		}
//	}
//  return elf_header.e_entry;
//}

static uintptr_t loader(PCB *pcb, const char *filename) {
	int fd = fs_open(filename,0,0);
	Elf64_Ehdr elf_header;	
	Elf64_Phdr program_header;
	size_t fpt_old;
	fs_read(fd,&elf_header,sizeof(elf_header));
	assert(*((uint32_t*)elf_header.e_ident) ==1179403647);
	fs_lseek(fd,elf_header.e_phoff,0);
	for(int i=0;i<elf_header.e_phnum;i++){
		fs_read(fd,&program_header,sizeof(program_header));
		fpt_old = fs_lseek(fd,0,1);
		if(program_header.p_type == PT_LOAD){
			fs_lseek(fd,program_header.p_offset,0);
			fs_read(fd,(void*)program_header.p_vaddr,program_header.p_memsz);	
			fs_lseek(fd,fpt_old,0);
			if(program_header.p_memsz >= program_header.p_filesz){
				memset((void*)program_header.p_vaddr + program_header.p_filesz,0,program_header.p_memsz-program_header.p_filesz);
			}
		}

	}
  return elf_header.e_entry;
}
void naive_uload(PCB *pcb, const char *filename) {
  uintptr_t entry = loader(pcb, filename);
  //Log("Jump to entry = %p", entry);
  ((void(*)())entry) ();
}

